/**
 * 创建用户模型
 */
var redis = require('redis');
var bcrypt = require('bcrypt');
var db = redis.createClient(6379, '192.168.2.54'); // 创建到Redis的长连接

module.exports = User; // 从这个模块中输出User函数

function User(obj) {
  for (var key in obj) { // 遍历传入对象中的键
    this[key] = obj[key]; // 合并值
  }
}

/**
 * 用户模型中的save实现
 */
User.prototype.save = function(fn) {
  if (this.id) {
    this.update(fn);
  } else {
    var user = this;
    db.incr('user:ids', function(err, id) { // 创建唯一ID
      user.id = id; // 设定ID，以便保存
      user.hashPassword(function(err) { // 密码哈希
        if (err) return fn(err);
        user.update(fn); // 保存用户属性
      });
    });
  }
};

User.prototype.update = function(fn) {
  var user = this;
  var id = user.id;
  db.set('user:id:' + user.name, id, function(err) { // 用名称索引用户ID
    if (err) return fn(err);
    db.hmset('user:' + id, user, function(err) { // 用Redis哈希存储数据
      fn(err);
    });
  });
};

/**
 * 在用户模型中添加bcrypt加密
 */
User.prototype.hashPassword = function(fn) {
  var user = this;
  bcrypt.genSalt(12, function(err, salt) { // 生成有12个字符的盐
    if (err) return fn(err);
    user.salt = salt; // 设定盐以便保存
    bcrypt.hash(user.pass, salt, function(err, hash) { // 生成哈希
      if (err) return fn(err);
      user.pass = hash; // 设定哈希以便保存
      fn();
    });
  });
};

/**
 * 从Redis中获取用户
 */
User.getByName = function(name, fn) {
  User.getId(name, function(err, id) { // 根据名称查找用户ID
    if (err) return fn(err);
    User.get(id, fn); // 用ID抓取用户
  });
};

User.getId = function(name, fn) {
  db.get('user:id:' + name, fn); // 取得由名称索引的ID
};

User.get = function(id, fn) {
  db.hgetall('user:' + id, function(err, user) { // 获取普通对象哈希
    if (err) return fn(err); 
    fn(null, new User(user)); // 将普通对象转换成新的User对象
  });
};

/**
 * 认证用户的名称和密码
 */
User.authenticate = function(name, pass, fn) {
  User.getByName(name, function(err, user) { // 通过名称查找用户
    if (err) return fn(err); 
    if (!user.id) return fn(); // 用户不存在
    bcrypt.hash(pass, user.salt, function(err, hash) { // 对给出的密码做哈希处理
      if (err) return fn(err);
      if (hash == user.pass) return fn(null, user); // 匹配发现项
      fn();
    });
  });
};

User.prototype.toJSON = function() {
  return {
    id: this.id,
    name: this.name
  };
};
